package com.lwq.fast.log.fastlogclient.log4j2.appender.util;

import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lwq.fast.log.fastlogcore.entity.Message;
import com.lwq.fast.log.fastlogcore.trace.TraceThreadLocal;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.ThrowableProxy;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;

/**
 * @author 刘文强
 */
public class MessageUtil {

    private final static String rn = "\r\n";

    /**
     *格式化日志
     *
     * @param appName 应用名称
     * @param env 环境信息
     * @param logEvent
     * @return Message
     */
    public static Message formatMessage(String appName, String env, LogEvent logEvent) {
        if (ObjectUtil.isNull(logEvent)){
            return null;
        }
        String content = logEvent.getMessage().getFormattedMessage();
        StrBuilder strBuilder = StrBuilder.create(content);
        if (StrUtil.equals(Level.ERROR.name(), logEvent.getLevel().name())){
            // 出现error 级别的日志，获取错误信息
            ThrowableProxy thrownProxy = logEvent.getThrownProxy();
            Object errorStackTrace = getErrorStackTrace(thrownProxy.getThrowable());
            strBuilder.append(errorStackTrace);
        }
        content = strBuilder.toString();
        return  Message.builder().env(env)
                .appName(appName)
                .threadName(logEvent.getThreadName())
                .level(logEvent.getLevel().name())
                .traceId(StrUtil.isBlank(TraceThreadLocal.get()) ? IdUtil.simpleUUID() : TraceThreadLocal.get())
                .className(logEvent.getLoggerName())
                .content(content)
                .dateTime(new Date(logEvent.getTimeMillis()))
                .build();
    }

    /**
     * 获取错误堆栈信息
     *
     * @param errorObj
     * @return
     */
    private static Object getErrorStackTrace(Object errorObj) {
        if (errorObj instanceof Exception) {
            Exception exception = (Exception) errorObj;
            StringWriter stringWriter = new StringWriter();
            PrintWriter printWriter = new PrintWriter(stringWriter);
            String stackTrace = rn;
            try {
                exception.printStackTrace(printWriter);
                stackTrace = stringWriter.toString();
                return stackTrace;
            } catch (Exception e) {
                e.printStackTrace();
                return errorObj;
            } finally {
                try {
                    printWriter.close();
                    stringWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else if(errorObj instanceof Error){
            Error error = (Error) errorObj;
            StringWriter stringWriter = new StringWriter();
            PrintWriter printWriter = new PrintWriter(stringWriter);
            String stackTrace = rn;
            try {
                error.printStackTrace(printWriter);
                stackTrace = stringWriter.toString();
                return stackTrace;
            } catch (Exception e) {
                e.printStackTrace();
                return errorObj;
            } finally {
                try {
                    printWriter.close();
                    stringWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }else {
            return errorObj;
        }
    }
}
